package tipoToken;

import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Clase que indica el tipo de Token.
 *
 * @author PLG Grupo 6
 */
public class TipoToken {

    private Tipos denominacion;
    private int posTablaSimbolos; // para tipo identificador

    public TipoToken(){
        denominacion = null;
        posTablaSimbolos = 0;
    };

    public void setTipo(Tipos valor){
        denominacion = valor;
    }

    public Tipos dameTipo(){
        return denominacion;
    }

    public void setPosicionTB(int pos) {
        if (denominacion == Tipos.IDENTIFICADOR) {
            posTablaSimbolos = pos;
        } else {
            System.out.println("Error no es un token tipo identificador");
        }
    }

    public int getPosicionTB() {
        if (denominacion == Tipos.IDENTIFICADOR) {
            return posTablaSimbolos;
        } else {
            System.out.println("Error no es un token tipo identificador");
        }
        return 0;
    }

    public String dameValor(){
        switch (denominacion){
            case ASIGNACION:
                return "Asignacion";
            case COMENTARIO:
                return "Comentario";
            case ERROR:
                return "Error";
            case FIN:
                return "Fin";
            case IDENTIFICADOR:
                return "Identificador";
            case NUM_ENTERO:
                return "NumeroEntero";
            case NUM_REAL:
                return "NumeroReal";
            case OPERADOR:
                return "Operador";
            case PALABRA_RESERVADA:
                return "PalabraReservada";
            case SALTO_LINEA:
                return "SaltoLinea";
            case SEPARADOR:
                return "Separador";
            case STRING:
                return "String";
            case TYPE_SPECIFIER:
                return "EspecificadorTipo";
            case ErrorIdentifierTooLarge:
                return "Error: Identificador demasiado largo";
            case ErrorIllegalChar:
                return "Error: Caracter ilegal";
            case ErrorInvalidIdentifier:
                return "Error: Identificador invalido";
            case ErrorInvalidString:
                return "Error: String inválido";
        }
        return null;
    }

    /**
     * Devuelve true si el lexema recibido corresponde a un operador de comparaci�n y false en caso contrario
     * @param lexema
     * @return
     */
    public static boolean tipoOperadorComp(String lexema) {
    	return (lexema.equals("<") || lexema.equals(">") ||
                lexema.equals("<>") || lexema.equals(">=") ||
                lexema.equals("<=") || lexema.equals("="));
    }

    /**
     * Devuelve true si el lexema recibido corresponde a una palabra reservada y false en caso contrario
     * @param lexema
     * @return
     */
    public static boolean tipoPalabraReservada(String lexema, String[] reservadas) {
        for (int i=0;i<reservadas.length;i++) {
            //Convierte todas las letras a mayuscula para comparar
            if(reservadas[i].equals(lexema.toUpperCase()))
                return true;
        }
        return false;
    }

    /**
     * Devuelve true si el lexema recibido corresponde a un operador de asignaci�n y false en caso contrario
     * @param lexema
     * @return
     */
    public static boolean tipoOperadorAsig(String lexema) {
        return (lexema.equals("="));
    }

    /**
     * Devuelve true si el lexema recibido corresponde a un identificador y false en caso contrario
     * @param lexema
     * @return
     */
    public static boolean tipoIdentificador(String lexema) {
    	//Compilamos el patron
        //El patron: No puede empezar con digito ni con _ y no puede contener punto
        Pattern patron = Pattern.compile("[a-zA-Z][a-zA-Z0-9_]*");
        // creamos el Matcher a partir del patron, y la cadena como parametro
        Matcher encajador = patron.matcher(lexema);
        return encajador.matches();//Si la cadena encaja con el patron true, en caso contrario false
    }

    /**
     * Devuelve true si el lexema recibido corresponde a un numero real y false en caso contrario
     * @param lexema
     * @return
     */
    public static boolean tipoNumeroReal(String lexema) {
        //Compilamos el patron
        //El patron: Un cero o un digito distinto de cero seguido de 0 o muchos digitos,
        //           seguidos de punto y uno o varios digitos. Ej: 0.2345, 23562.0854
        Pattern patron = Pattern.compile("(0|[1-9][0-9]*)\\.[0-9]+");
        // creamos el Matcher a partir del patron, y la cadena como parametro
        Matcher encajador = patron.matcher(lexema);
        return encajador.matches();//Si la cadena encaja con el patron true, en caso contrario false
    }

    /**
     * Devuelve true si el lexema recibido corresponde a un numero entero y false en caso contrario
     * @param lexema
     * @return
     */
    public static boolean tipoNumeroEntero(String lexema) {
        if(lexema.equals("0"))
            return true;
        else
        {
            //Compilamos el patron
            //El patron: Un digito distinto de cero seguido de 0 o muchos digitos. Ej: 1, 242, 2345
            Pattern patron = Pattern.compile("[1-9][0-9]*");
            // creamos el Matcher a partir del patron, y la cadena como parametro
            Matcher encajador = patron.matcher(lexema);
            return encajador.matches();//Si la cadena encaja con el patron true, en caso contrario false
        }
    }

    /**
     * Devuelve true si el token recibido tiene formato correcto para un comentario, en caso contrario devuelve false
     * @param lexema
     * @return
     */
    public static boolean tipoComentario(String lexema) {
        //Compilamos el patron
        //El patron: Cadena que comienza por el caracter ' seguido de una sucesion de cualquier caracter finalizando en \n
        Pattern patron = Pattern.compile("'.*");
        // creamos el Matcher a partir del patron, y la cadena como parametro
        Matcher encajador = patron.matcher(lexema);
        return encajador.matches();//Si la cadena encaja con el patron true, en caso contrario false
    }

    /**
     * Devuelve true si el token recibido tiene formato correcto para un string, en caso contrario devuelve false
     * @param lexema
     * @return
     */
    public static boolean tipoString(String lexema) {
        //Compilamos el patron
        //El patron: Cadena que comienza por el caracter ' seguido de una sucesion de cualquier caracter finalizando en \"
        Pattern patron = Pattern.compile("\"[^\"]*\"");
        // creamos el Matcher a partir del patron, y la cadena como parametro
        Matcher encajador = patron.matcher(lexema);
        return encajador.matches();//Si la cadena encaja con el patron true, en caso contrario false
    }

    /**
     * Comprueba si el lexema en formato string corresponde a un numero
     * @param lexema
     * @return True si la cadena es un número, false en caso contrario
     */
    public static boolean tokenIsNumber(String lexema) {
        try{
            int numero = Integer.parseInt(lexema);
            return true;
        }catch(NumberFormatException e){
            //La cadena no es un numero
            return false;
        }
    }

    /**
     *Recibe un token que corresponde al inicio de un numero y devuelve la posicion en la que termina
     * @param lexema
     * @param tokenizer
     * @return
     */
    public static int tokenIsStartOfNumber(String lexema, ArrayList listaTokens, int currentPos) {
        currentPos++;
        String aux = (String)listaTokens.get(currentPos);
        if(aux.equals("."))
        {
            currentPos++;
            String next = (String)listaTokens.get(currentPos);
            while(!tokenIsDelim(next) || next.equals("."))
            {
                currentPos++;
                next = (String)listaTokens.get(currentPos);
            }
        }
        currentPos--;
        return currentPos;
    }

    /**
     * Recibe un token que corresponde al inicio de un comentario y devuelve el string entero del comentario
     * @param lexema
     * @param tokenizer
     * @return Comentario completo, com un único token
     */
    public static int tokenIsStartOfComment(String lexema, ArrayList listaTokens, int currentPos) {
        String next = (String)listaTokens.get(currentPos);
        while(!next.equals("\n"))
        {
            currentPos++;
            next = (String)listaTokens.get(currentPos);
        }
        return --currentPos;
    }

    /**
     * Recibe un token que corresponde al inicio de un string y devuelve la posicion en la que termina
     * @param lexema
     * @param tokenizer
     * @return
     */
    public static int tokenIsStartOfString(String lexema, ArrayList listaTokens, int currentPos) {
        //Si el string es "", directamente return
        if(!lexema.equals("\"\""))
        {
            //Miramos si el string esta ya cerrado. Ejemplo: "hola"
            Pattern patron = Pattern.compile("\"[^\"]*\"");
            // creamos el Matcher a partir del patron, y la cadena como parametro
            Matcher encajador = patron.matcher(lexema);
            if(!encajador.matches())//Si no esta cerrado
            {
                currentPos++;
                String next = (String)listaTokens.get(currentPos);
                while( (!next.endsWith("\"")) && !(next.equals("\n")) )
                {//Mientras que el caracter no sea " ni \n, seguir leyendo
                    currentPos++;
                    next = (String)listaTokens.get(currentPos);
                }//Las siguientes lineas son para concatenar el " del final del string, si es que llega ese caracter
                if(next.equals("\n"))
                  System.out.println("Error al escribir la cadena");
            }
        }
        return currentPos;
    }

    /**
     * Devuelve true si el lexema recibido corresponde a un delimitador y false en caso contrario
     * @param lexema
     * @return
     */
    public static boolean tokenIsDelim(String lexema) {
        return (lexema.equals(" ") ||
               lexema.equals(".") ||
               lexema.equals(",") ||
               lexema.equals(":") ||
               lexema.equals(";") ||
               lexema.equals("+") ||
               lexema.equals("-") ||
               lexema.equals("*") ||
               lexema.equals("/") ||
               lexema.equals("(") ||
               lexema.equals(")") ||
               lexema.equals("!") ||
               lexema.equals("#") ||
               lexema.equals("$") ||
               lexema.equals("%") ||
               lexema.equals("&") ||
               lexema.equals("\t")||
               lexema.equals("\n"));
    }

    /**
     * Devuelve true si el token recibido es el operador de asignación (=)
     * @param lexema
     * @return
     */
    public static boolean tokenIsAsignacion(String lexema) {
        return lexema.equals("=");
    }

    /**
     * Devuelve true si el lexema introducido corresponde a un simbolo especificador de tipo
     * @param lexema
     * @return
     */
    public static boolean tokenIsTypeSpecifier(String lexema) {
        return (lexema.equals("%") ||
               lexema.equals("$") ||
               lexema.equals("#") ||
               lexema.equals("!") ||
               lexema.equals("&"));
    }

    /**
     * Devuelve true si el lexema introducido corresponde a un separador
     * @param lexema
     * @return
     */
    public static boolean tokenIsSeparator(String lexema) {
        return (lexema.equals("+") ||
               lexema.equals("-") ||
               lexema.equals("*") ||
               lexema.equals("/") ||
               lexema.equals("(") ||
               lexema.equals(")") ||
               lexema.equals(",") ||
               lexema.equals(";") ||
               lexema.equals(":") ||
               lexema.equals("!") ||
               lexema.equals("."));
    }

    /**
     * Devuelve true en el caso de que el token recibido sea un operador aritmetico
     * @param lexema
     * @return
     */
    public static boolean tokenIsOperator(String lexema) {
        return (lexema.equals("+")|| lexema.equals("-")||
                lexema.equals("*")|| lexema.equals("/"));
    }

    /**
     * Devuelve true en el caso de que el token recibido sea un salto de linea
     * @param lexema
     * @return
     */
    public static boolean tokenIsNewLine(String lexema) {
        return lexema.equals("\n");
    }
}
